{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import math\n",
    "from sklearn.model_selection import train_test_split\n",
    "from data import *\n",
    "from evaluation import *\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 读取数据 并展示"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "data_col = ['user_id','item_id','rating','timestamp']\n",
    " \n",
    "item_col = ['movie_id','movie_title','release_date','video_release_date','IMDb_URL','unknown','Action',\n",
    "           'Adventure','Animation',\"Children's\",'Comedy','Crime','Documentary','Drama','Fantasy',\n",
    "           'Film-Noir','Horror','Musical','Mystery','Romance','Sci-Fi','Thriller','War','Western']\n",
    " \n",
    "#总数据包含了用户，物品，评分\n",
    "data_dir = 'datasets/ml-100k/u.data' \n",
    "data = pd.read_table(data_dir,header=None, names=data_col, parse_dates=['timestamp'])\n",
    " \n",
    "#物品详细数据\n",
    "item_dir = 'datasets/ml-100k/u.item'\n",
    "item = pd.read_table(item_dir, header=None, names=item_col, parse_dates=['release_date','video_release_date'], encoding='ISO-8859-1', sep='|')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>movie_id</th>\n",
       "      <th>movie_title</th>\n",
       "      <th>release_date</th>\n",
       "      <th>video_release_date</th>\n",
       "      <th>IMDb_URL</th>\n",
       "      <th>unknown</th>\n",
       "      <th>Action</th>\n",
       "      <th>Adventure</th>\n",
       "      <th>Animation</th>\n",
       "      <th>Children's</th>\n",
       "      <th>...</th>\n",
       "      <th>Fantasy</th>\n",
       "      <th>Film-Noir</th>\n",
       "      <th>Horror</th>\n",
       "      <th>Musical</th>\n",
       "      <th>Mystery</th>\n",
       "      <th>Romance</th>\n",
       "      <th>Sci-Fi</th>\n",
       "      <th>Thriller</th>\n",
       "      <th>War</th>\n",
       "      <th>Western</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>Toy Story (1995)</td>\n",
       "      <td>1995-01-01</td>\n",
       "      <td>NaT</td>\n",
       "      <td>http://us.imdb.com/M/title-exact?Toy%20Story%2...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2</td>\n",
       "      <td>GoldenEye (1995)</td>\n",
       "      <td>1995-01-01</td>\n",
       "      <td>NaT</td>\n",
       "      <td>http://us.imdb.com/M/title-exact?GoldenEye%20(...</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>3</td>\n",
       "      <td>Four Rooms (1995)</td>\n",
       "      <td>1995-01-01</td>\n",
       "      <td>NaT</td>\n",
       "      <td>http://us.imdb.com/M/title-exact?Four%20Rooms%...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>4</td>\n",
       "      <td>Get Shorty (1995)</td>\n",
       "      <td>1995-01-01</td>\n",
       "      <td>NaT</td>\n",
       "      <td>http://us.imdb.com/M/title-exact?Get%20Shorty%...</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>5</td>\n",
       "      <td>Copycat (1995)</td>\n",
       "      <td>1995-01-01</td>\n",
       "      <td>NaT</td>\n",
       "      <td>http://us.imdb.com/M/title-exact?Copycat%20(1995)</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>5 rows × 24 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "   movie_id        movie_title release_date video_release_date  \\\n",
       "0         1   Toy Story (1995)   1995-01-01                NaT   \n",
       "1         2   GoldenEye (1995)   1995-01-01                NaT   \n",
       "2         3  Four Rooms (1995)   1995-01-01                NaT   \n",
       "3         4  Get Shorty (1995)   1995-01-01                NaT   \n",
       "4         5     Copycat (1995)   1995-01-01                NaT   \n",
       "\n",
       "                                            IMDb_URL  unknown  Action  \\\n",
       "0  http://us.imdb.com/M/title-exact?Toy%20Story%2...        0       0   \n",
       "1  http://us.imdb.com/M/title-exact?GoldenEye%20(...        0       1   \n",
       "2  http://us.imdb.com/M/title-exact?Four%20Rooms%...        0       0   \n",
       "3  http://us.imdb.com/M/title-exact?Get%20Shorty%...        0       1   \n",
       "4  http://us.imdb.com/M/title-exact?Copycat%20(1995)        0       0   \n",
       "\n",
       "   Adventure  Animation  Children's   ...     Fantasy  Film-Noir  Horror  \\\n",
       "0          0          1           1   ...           0          0       0   \n",
       "1          1          0           0   ...           0          0       0   \n",
       "2          0          0           0   ...           0          0       0   \n",
       "3          0          0           0   ...           0          0       0   \n",
       "4          0          0           0   ...           0          0       0   \n",
       "\n",
       "   Musical  Mystery  Romance  Sci-Fi  Thriller  War  Western  \n",
       "0        0        0        0       0         0    0        0  \n",
       "1        0        0        0       0         1    0        0  \n",
       "2        0        0        0       0         1    0        0  \n",
       "3        0        0        0       0         0    0        0  \n",
       "4        0        0        0       0         1    0        0  \n",
       "\n",
       "[5 rows x 24 columns]"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "item.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item_id</th>\n",
       "      <th>rating</th>\n",
       "      <th>timestamp</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>196</td>\n",
       "      <td>242</td>\n",
       "      <td>3</td>\n",
       "      <td>881250949</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>186</td>\n",
       "      <td>302</td>\n",
       "      <td>3</td>\n",
       "      <td>891717742</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>22</td>\n",
       "      <td>377</td>\n",
       "      <td>1</td>\n",
       "      <td>878887116</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>244</td>\n",
       "      <td>51</td>\n",
       "      <td>2</td>\n",
       "      <td>880606923</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>166</td>\n",
       "      <td>346</td>\n",
       "      <td>1</td>\n",
       "      <td>886397596</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   user_id  item_id  rating  timestamp\n",
       "0      196      242       3  881250949\n",
       "1      186      302       3  891717742\n",
       "2       22      377       1  878887116\n",
       "3      244       51       2  880606923\n",
       "4      166      346       1  886397596"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 加载数据\n",
    "#### 将id标准化：新id从0开始按1递增，输出格式：(user, item, rating)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " data length: 100000 \n",
      " user number: 943 \n",
      " item number: 1682\n"
     ]
    }
   ],
   "source": [
    "N, M, data_list, item_ids_dict = load_data(file_dir=data_dir)\n",
    "print(' data length: %d \\n user number: %d \\n item number: %d' %(len(data_list),N,M))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>new_id</th>\n",
       "      <th>movie_id</th>\n",
       "      <th>movie_title</th>\n",
       "      <th>release_date</th>\n",
       "      <th>video_release_date</th>\n",
       "      <th>IMDb_URL</th>\n",
       "      <th>unknown</th>\n",
       "      <th>Action</th>\n",
       "      <th>Adventure</th>\n",
       "      <th>Animation</th>\n",
       "      <th>...</th>\n",
       "      <th>Fantasy</th>\n",
       "      <th>Film-Noir</th>\n",
       "      <th>Horror</th>\n",
       "      <th>Musical</th>\n",
       "      <th>Mystery</th>\n",
       "      <th>Romance</th>\n",
       "      <th>Sci-Fi</th>\n",
       "      <th>Thriller</th>\n",
       "      <th>War</th>\n",
       "      <th>Western</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>242</td>\n",
       "      <td>Kolya (1996)</td>\n",
       "      <td>1997-01-24</td>\n",
       "      <td>NaT</td>\n",
       "      <td>http://us.imdb.com/M/title-exact?Kolya%20(1996)</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>302</td>\n",
       "      <td>L.A. Confidential (1997)</td>\n",
       "      <td>1997-01-01</td>\n",
       "      <td>NaT</td>\n",
       "      <td>http://us.imdb.com/M/title-exact?L%2EA%2E+Conf...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2</td>\n",
       "      <td>377</td>\n",
       "      <td>Heavyweights (1994)</td>\n",
       "      <td>1994-01-01</td>\n",
       "      <td>NaT</td>\n",
       "      <td>http://us.imdb.com/M/title-exact?Heavyweights%...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>3</td>\n",
       "      <td>51</td>\n",
       "      <td>Legends of the Fall (1994)</td>\n",
       "      <td>1994-01-01</td>\n",
       "      <td>NaT</td>\n",
       "      <td>http://us.imdb.com/M/title-exact?Legends%20of%...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>4</td>\n",
       "      <td>346</td>\n",
       "      <td>Jackie Brown (1997)</td>\n",
       "      <td>1997-01-01</td>\n",
       "      <td>NaT</td>\n",
       "      <td>http://us.imdb.com/M/title-exact?imdb-title-11...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>5 rows × 25 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "   new_id  movie_id                 movie_title release_date  \\\n",
       "0       0       242                Kolya (1996)   1997-01-24   \n",
       "1       1       302    L.A. Confidential (1997)   1997-01-01   \n",
       "2       2       377         Heavyweights (1994)   1994-01-01   \n",
       "3       3        51  Legends of the Fall (1994)   1994-01-01   \n",
       "4       4       346         Jackie Brown (1997)   1997-01-01   \n",
       "\n",
       "  video_release_date                                           IMDb_URL  \\\n",
       "0                NaT    http://us.imdb.com/M/title-exact?Kolya%20(1996)   \n",
       "1                NaT  http://us.imdb.com/M/title-exact?L%2EA%2E+Conf...   \n",
       "2                NaT  http://us.imdb.com/M/title-exact?Heavyweights%...   \n",
       "3                NaT  http://us.imdb.com/M/title-exact?Legends%20of%...   \n",
       "4                NaT  http://us.imdb.com/M/title-exact?imdb-title-11...   \n",
       "\n",
       "   unknown  Action  Adventure  Animation   ...     Fantasy  Film-Noir  Horror  \\\n",
       "0        0       0          0          0   ...           0          0       0   \n",
       "1        0       0          0          0   ...           0          1       0   \n",
       "2        0       0          0          0   ...           0          0       0   \n",
       "3        0       0          0          0   ...           0          0       0   \n",
       "4        0       0          0          0   ...           0          0       0   \n",
       "\n",
       "   Musical  Mystery  Romance  Sci-Fi  Thriller  War  Western  \n",
       "0        0        0        0       0         0    0        0  \n",
       "1        0        1        0       0         1    0        0  \n",
       "2        0        0        0       0         0    0        0  \n",
       "3        0        0        1       0         0    1        1  \n",
       "4        0        0        0       0         0    0        0  \n",
       "\n",
       "[5 rows x 25 columns]"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "new_item_information = item.insert(0,'new_id',[item_ids_dict[old_idx] for old_idx in item['movie_id']])\n",
    "item.sort_values('new_id',inplace=False).set_index(['new_id']).reset_index().head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 分割数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train length: 80000 \n",
      " test length: 20000\n"
     ]
    }
   ],
   "source": [
    "train_list, test_list = train_test_split(data_list,test_size=0.2)\n",
    "print ('train length: %d \\n test length: %d' %(len(train_list),len(test_list)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 转化数据成矩阵格式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 3.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  2.,  0.,  0.,\n",
       "        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,\n",
       "        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,\n",
       "        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,\n",
       "        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,\n",
       "        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,\n",
       "        0.,  0.,  0.,  0.,  0.,  4.,  0.,  0.,  4.,  0.,  0.,  0.,  0.,\n",
       "        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_mat = sequence2mat(sequence = train_list, N = N, M = M)\n",
    "test_mat = sequence2mat(sequence = test_list, N = N, M = M)\n",
    "train_mat[0,:100]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 计算相似度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 计算 a 和 b 之间相似度\n",
    "def calculate_similarity(a, b, model='pearson', minimum_common_items=5):\n",
    "    assert a.shape==b.shape\n",
    "    dim = len(a.shape) #向量维度\n",
    "    common_items = a*b>0 # 共同评分的项\n",
    "    common_size = np.sum(common_items,axis=dim-1)\n",
    "    \n",
    "    if model=='pearson':\n",
    "        mean_a = np.sum(a,axis=dim-1)/np.sum(a>0,axis=dim-1)\n",
    "        mean_b = np.sum(b,axis=dim-1)/np.sum(b>0,axis=dim-1)\n",
    "        if dim ==1: #若是两个列向量\n",
    "            aa = (a - mean_a)*common_items\n",
    "            bb = (b - mean_b)*common_items\n",
    "        else:\n",
    "            aa = (a - np.reshape(mean_a, (-1,1)))*common_items\n",
    "            bb = (b - np.reshape(mean_b, (-1,1)))*common_items\n",
    "    else: #consine\n",
    "        mean_u = np.sum(b,axis=0)/np.sum(b>0,axis=0)\n",
    "        aa = (a - mean_u)*common_items\n",
    "        bb = (b - mean_u)*common_items\n",
    "        \n",
    "    sim = np.sum(aa*bb, axis=dim-1)/(np.sqrt(np.sum(aa**2, axis=dim-1))*np.sqrt(np.sum(bb**2, axis=dim-1)) + 1e-10)\n",
    "    least_common_items = common_size>minimum_common_items # 共同评分的商品不少于least_common_items\n",
    "    return sim*least_common_items\n",
    "\n",
    "\n",
    "# 计算相似度\n",
    "def similarity_matrix(mat, model='pearson', minimum_common_items=5):\n",
    "    n,m = mat.shape\n",
    "    sim_list=[]\n",
    "    for u in range(n):\n",
    "        a = np.tile(mat[u,:], (n,1))\n",
    "        b = mat\n",
    "        if model=='pearson':\n",
    "            sim = calculate_similarity(a, b, model='pearson', minimum_common_items=minimum_common_items)\n",
    "        else: # consine\n",
    "            sim = calculate_similarity(a, b, model='consine', minimum_common_items=minimum_common_items)\n",
    "        sim_list.append(sim)\n",
    "        if u % 100 ==0:\n",
    "            print(u)\n",
    "    return np.array(sim_list) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "100\n",
      "200\n",
      "300\n",
      "400\n",
      "500\n",
      "600\n",
      "700\n",
      "800\n",
      "900\n"
     ]
    }
   ],
   "source": [
    "sim_mat = similarity_matrix(mat=train_mat, model='pearson')\n",
    "neighbors = np.argsort(-np.array(sim_mat)) # 获取近邻\n",
    "sim_sort = -1*np.sort(-np.array(sim_mat)) # 获取对应近邻的相似度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "user 0:\n",
      "neighbors:\n",
      "[  0  20  87 887 123  25 660 928 876  54]\n",
      "sim:\n",
      "\n",
      "[ 1.      0.8112  0.7276  0.7175  0.7076  0.7043  0.6884  0.6744  0.654\n",
      "  0.6533]\n",
      "similarity_mat:\n",
      "[[ 1.     -0.      0.3777 -0.1348 -0.      0.0008]\n",
      " [-0.      1.      0.427  -0.0791  0.      0.0339]\n",
      " [ 0.3777  0.427   1.      0.1021  0.      0.3127]\n",
      " [-0.1348 -0.0791  0.1021  1.      0.     -0.0071]\n",
      " [-0.      0.      0.      0.      1.      0.    ]\n",
      " [ 0.0008  0.0339  0.3127 -0.0071  0.      1.    ]]\n"
     ]
    }
   ],
   "source": [
    "np.set_printoptions(precision=4, suppress=True)\n",
    "print('user 0:')\n",
    "print('neighbors:') # 用户0的近邻\n",
    "print(neighbors[0,:10])\n",
    "print('sim:\\n') # 用户0 的近邻相似度\n",
    "print(sim_sort[0,:10])\n",
    "print('similarity_mat:') # 用户之间的相似度矩阵\n",
    "print(sim_mat[:6,:6])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 近邻Ｋ的取值\n",
    "经验取值：一般取 10-50 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def get_K(sim_mat, min_similarity=0.5):\n",
    "    num = np.sum(sim_mat[:,1:]>min_similarity, axis=1) #统计用户大于min_similarity的评分数\n",
    "    \n",
    "    # 画图 \n",
    "    plt.rcParams['font.sans-serif'] = [u'SimHei']\n",
    "    plt.rcParams['axes.unicode_minus'] = False\n",
    "    plt.hist(num, bins=40, normed=0, facecolor=\"blue\", edgecolor=\"black\", alpha=0.7)\n",
    "    plt.xlabel(u\"人数/商品数\")\n",
    "    plt.ylabel(u\"次数\")\n",
    "    plt.title(u\"人数/商品数-次数分布直方图\")\n",
    "    plt.show()\n",
    "    \n",
    "    num_sort = np.sort(-num)\n",
    "    line = int(0.8*len(sim_mat))\n",
    "    K = -1*num_sort[line]\n",
    "    return K"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\nSUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0xc3f8240>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('min_similarity:', 0.8, 'K:', 3)\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nmZlZCwpruYiIKyQdDrwV2A+4EXhFRIxJWgH0SzofGANOKipOMzMza02R3SJExLnAuTW2r80W2eol\nTUvdPOnBmZmZ2S4pNLloJCLuIc0eMTMzsynENy4zMzOzXDm5MDMzs1w5uTAzM7NcObkwMzOzXDm5\nMDMzs1w5uTAzM7Ncte1UVGsvg4ODlEqlcct1d3ezcOHCSYjIzMzalZMLG9fg4CDLlp3G0NDIuGUX\nLOhkzZqLnWCYme3BnFzYuEqlEkNDI3R2rqKra1HdcsPDGxkauoBSqeTkwsxsD+bkwprW1bWIuXMX\nNywzMn7jxkPc1WJmNj05ubBCuKvFzGz6cnJhhXBXi5nZ9OXkwgqVd1eLmZkVz+tcmJmZWa6cXJiZ\nmVmunFyYmZlZrpxcmJmZWa6cXJiZmVmunFyYmZlZrpxcmJmZWa6cXJiZmVmunFyYmZlZrgpNLiQt\nl7RD0lj2s/x4g6QjJV0naUjSeUXGaWZmZs0ruuXiMmA+sHf2cxEwCPwEWAtcDxwHLJG0vKggzczM\nrHmFJhcRMRoRpfIDWA5cCSwBuoFVEbEBOAdYUWCoZmZm1qS2uXGZpE7gTOB44I3AuojYChARN0ha\nUmB4ZmZm1qSiu0UqvZaUUPyO1GqxoWr/qKSeyQ/LzMzMWtE2LRfA3wLvyX4frbF/BJgDbKl3gJUr\nV9LTs3P+0dfXR19fX14xmpmZTVn9/f309/fvtG3LlrqX1V3WFsmFpEOBxcA12aZNwJFVxeYB2xod\nZ/Xq1SxdujT/AM3MzKaBWl+4169fT29vb67naZdukVOAr0XEWPb8euCE8k5JBwMdpKTDzMzM2li7\nJBcvAL5b8fz7wLyK6adnA9dEREx2YGZmZtaawrtFJM0mzRA5tbwtIsYknQr0SzofGANOKiZCMzMz\na0XhyUU23bSrxva1kg4BekmzSDZPenBmZmbWssKTi0Yi4h7g6qLjmK4GBwcplUrjlhsYGGB0tNYE\nHjMzs0dq6+TCJs7g4CDLlp3G0NDIuGVHRh5g48a76ekZv6yZmZmTiz1UqVRiaGiEzs5VdHUtalh2\n8+Z1jI6ey+joWMNyZmZm4ORij9fVtYi5cxc3LDM8PDBJ0ZiZ2XTQLlNRzczMbJpwcmFmZma5cnJh\nZmZmuXJyYWZmZrlycmFmZma5cnJhZmZmuXJyYWZmZrlycmFmZma5cnJhZmZmuXJyYWZmZrlycmFm\n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\nWTtxcmE2BTRzkzPf4MzM2oUHdJqZmVmunFyYmZlZrpxcmJmZWa6cXJiZmVmunFyYmZlZrpxcmJmZ\nWa6cXJiZmVmunFyYmZlZrpxcmJmZWa6cXJiZmVmunFyYmZlZrpxcmJmZWa6cXJiZmVmunFyYmZlZ\nrvb4W64PDg5SKpUalhkYGGB0dHSSIjIzM5va9ujkYnBwkGXLTmNoaKRhuZGRB9i48W56ehqXMzMz\nsz08uSiVSgwNjdDZuYqurkV1y23evI7R0XMZHR2bxOjMzMympkKTC0kvAz4CPA64EeiLiFslHQV8\nGlgMXBIRZ01kHF1di5g7d3Hd/cPDAxN5ejMzs2mlsAGdkg4hJRDvAPYHfg1cIqkDWAtcDxwHLJG0\nvKg4zczMrDVFzhY5AjgrIq6IiEHgYuBY4IXAPGBVRGwAzgFWFBemmZmZtaKwbpGIuKpq02Gk1osn\nAesiYmtW7gZJSyY7PjMzM9s1bTGgU9IsYBVwAfAEYENVkVFJPRGxZdKDM5uGmpmCDdDd3c3ChQsn\nISIzm07aIrkA3gvcD1wCnFtj/wgwB2iYXKxcuZKenp6dtvX19dHX15dTmGZTX7NTsAEWLOhkzZqL\nnWCYTRP9/f309/fvtG3Llvy/txeeXEh6DnAa8JSIGJO0CTiyqtg8YNt4x1q9ejVLly6dgCjNpo9m\np2APD29kaOgCSqWSkwuzaaLWF+7169fT29ub63mKnop6MLAGOD0ibs02Xw+cWlWmA9g0+RGaTV/j\nTcEGGPG6cWa2C4qcijob+BrwZeArkuZKmgv8AJhXMf30bOCaiIiCQjUzM7MWFNly8RfA4dnjVEBA\nAAdnz/slnQ+MAScVFKOZmZm1qMipqF8FZtTZ/btska1e0rTUzZMXmZmZme2Owgd01hMR9wBXFx2H\nmZmZtabIFTrNzMxsGnJyYWZmZrlycmFmZma5cnJhZmZmuXJyYWZmZrlycmFmZma5cnJhZmZmuXJy\nYWZmZrlycmFmZma5cnJhZmZmuXJyYWZmZrlycmFmZma5atsbl+2qkZERvvSlL7Ft27Zxy957773s\n2LFjEqIyMzPbc0y75OJb3/oW73//GiIeO27ZkZHb2bFjhH32mYTAzMzM9hDTLrnYsWMHO3Z0ceih\nnxy37M03v5KIuyYhKjMzsz2Hx1yYmZlZrpxcmJmZWa6cXJiZmVmunFyYmZlZrqbdgE4zy8/27SMM\n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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x11d3b198>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('min_similarity:', 0.5, 'K:', 32)\n"
     ]
    }
   ],
   "source": [
    "min_similarity=0.8\n",
    "K = get_K(sim_mat, min_similarity=min_similarity)\n",
    "print('min_similarity:',min_similarity,'K:',K)\n",
    "\n",
    "min_similarity=0.5\n",
    "K = get_K(sim_mat, min_similarity=min_similarity)\n",
    "print('min_similarity:',min_similarity,'K:',K)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 预测用户未知项的评分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def prediction(train_mat, sim_mat, K=1, model='user_based'):\n",
    "    assert len(train_mat.shape)>1\n",
    "    n,m = train_mat.shape\n",
    "    \n",
    "    if  model=='user_based':\n",
    "        sim_sort = -1*np.sort(-np.array(sim_mat))[:,1:K+1] # 除去最相似的自己\n",
    "        neighbors = np.argsort(-np.array(sim_mat))[:,1:K+1]\n",
    "        common_items = train_mat[neighbors]>0 \n",
    "        mean_user = np.reshape(np.sum(train_mat,axis=1)/np.sum(train_mat>0,axis=1), (-1,1))\n",
    "        mat_m = train_mat - mean_user\n",
    "        aa = np.sum(sim_sort[:,:,np.newaxis]*mat_m[neighbors]*common_items,axis=1)\n",
    "        bb = np.sum(sim_sort[:,:,np.newaxis]*common_items,axis=1)+1e-10 # 1e-10保证分母不为０\n",
    "        r_pred = mean_user + aa/bb\n",
    "        return r_pred\n",
    "    else: # 'item_based'\n",
    "        r_pred=[]\n",
    "        for u in range(n):\n",
    "            u_mat = np.tile(train_mat[u],(m,1)) # m份用户u的记录,m*m\n",
    "            rated_items_sim = (u_mat>0)*sim_mat # 保留有评分记录的相似度 m*m\n",
    "            sim_sort = -1*np.sort(-np.array(rated_items_sim))[:,:K] # m*K\n",
    "            neighbors = np.argsort(-np.array(rated_items_sim))[:,:K] # m*K\n",
    "            neighbor_ratings = np.array([u_mat[i,neighbors[i]] for i in range(m)])# m*K\n",
    "            aa = np.sum(sim_sort*neighbor_ratings,axis=1) # m*1\n",
    "            bb = np.sum(sim_sort,axis=1)+1e-10 # 1e-10保证分母不为０ m*1\n",
    "            r_pred.append(aa/bb)\n",
    "        \n",
    "        return np.array(r_pred)    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "r_pred = prediction(train_mat=train_mat, sim_mat=sim_mat, K=K, model='user_based')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 根据预测值　对商品进行排序　获取top-n列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "user 0:\n",
      "('top-n list:', array([ 533,  785, 1432,  984,  572, 1281, 1279,  410,  782,  806], dtype=int64))\n"
     ]
    }
   ],
   "source": [
    "n = 10\n",
    "topn = get_topn(r_pred=r_pred, train_mat=train_mat, n=n)\n",
    "print('user 0:')\n",
    "print('top-n list:',topn[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 评估模型\n",
    "$$\n",
    " MAE = \\frac{1}{\\left | R_{test} \\right |} \\sum_{\\left ( u,i \\right ) \\in R_{test} }^{ } \\left | r_{u,i}-\\widehat{r}_{u,i} \\right |\n",
    "$$\n",
    "$$\n",
    "RMSE = \\sqrt{\\frac{1}{\\left | R_{test} \\right |} \\sum_{\\left ( u,i \\right ) \\in R_{test} }^{ } \\left (r_{u,i}-\\widehat{r}_{u,i} \\right )^2 }\n",
    "$$\n",
    "$$\n",
    "Recall = \\frac{hits}{\\left |R_{test} \\right |}\n",
    "$$\n",
    "$$\n",
    "Precision = \\frac{hits}{\\left |top\\_n \\right |}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "mae:0.8497; rmse:1.1711\n",
      "recall:0.0118; precision:0.0251\n"
     ]
    }
   ],
   "source": [
    "mae, rmse = mae_rmse(r_pred=r_pred, test_mat=test_mat)\n",
    "print('mae:%.4f; rmse:%.4f'%(mae,rmse))\n",
    "recall, precision = recall_precision(topn=topn, test_mat=test_mat)\n",
    "print('recall:%.4f; precision:%.4f'%(recall,precision))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 基于商品的近邻算法\n",
    "用户－商品的评分矩阵　$ R^{n×m} $　转置\n",
    "－>商品－用户的评分矩阵　$ R^{m×n} $"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "100\n",
      "200\n",
      "300\n",
      "400\n",
      "500\n",
      "600\n",
      "700\n",
      "800\n",
      "900\n",
      "1000\n",
      "1100\n",
      "1200\n",
      "1300\n",
      "1400\n",
      "1500\n",
      "1600\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nw8zMzMYHBx5mZmZWGAceZmZmVhgHHmZmZlYYBx5mZmZWGAceZmZmVhgHHmZmZlYYBx5mZmZWGAce\nZmZmVhgHHmZmZlYYBx5mZmZWGAceZmZmVhgHHmZmZlYYBx5mZmZWGAceZmZmVhgHHmZmZlYYBx5m\nZmZWGAceZmZmVhgHHmZmZlYYBx5mZmZWGAceZmZmVhgHHmZmZlaYtgg8JPVIeq6kHVtdFjMzMxs9\nLQ88JB0PPAB8EXhQ0uvz9jmSbpW0XNK5Fa+pmWZmZmbtq6WBh6Ru4BLgRRFxMPBu4HxJXcAC4Dbg\nMGCWpHn5NV3AtdXSzMzMrL21usWjG3hPRCzOzxcB04FXANOAMyJiCXA2MD/nOTa/rlqamZmZtbGW\nBh4R8YeI6AeQNBk4HbgGOBhYGBHrc747gQPzy+ZWSZtVdNnNzMysea1u8QBA0lzgT8AxwGmkFo0l\nFdkGJfXUSBvIaWZmZtbGJrW6AJBaLSS9DLgI+BLwuyrZ1gNTgYEqaRty2qpax1i8+HQmT946Npkx\no4+ZM/uGW2wzM7Mxo7+/n/7+/q22rVpV87I6bG0ReABExO2S3g7cB3wQmFORpRvYCKwAZlekTctp\nNc2efRE9PYeOTGHNzMzGmL6+Pvr6tv4yvmjRInp7e0f0OK2e1XKEpPPKNm0CNgN3A4eX5dsb6CIF\nHbfVSTMzM7M21uoxHvcC75Q0X9IewKeAG4Drge6yabJnATdGRAA3A9NqpJmZmVkba/WsloeB1wPv\nBX4FTAHmRcQgaYrsJZKWAccBZ+bXDAInVUszMzOz9tbyMR4RcRNPHc9BRCyQtA/QS5o+u7KRNDMz\nM2tfLQ886omIR0ndLk2lmZmZWXtq9RgPMzMzG0cceJiZmVlhHHiYmZlZYRx4mJmZWWEceJiZmVlh\nHHiYmZlZYRx4mJmZWWEceJiZmVlhHHiYmZlZYRx4mJmZWWEceJiZmVlhHHiYmZlZYRx4mJmZWWEc\neJiZmVlhHHiYmZlZYRx4mJmZWWEceJiZmVlhHHiYmZlZYRx4mJmZWWEceJiZmVlhHHiYmZlZYRx4\nmJmZWWFaGnhIeo2k+yRtkrRI0v55+8WSNksazD/vLXvNHEm3Slou6dzWld7MzMya1bLAQ9I+wJeB\nDwAzgN8Cl+XkXuAVwI75cUh+TRdwLXAbcBgwS9K8YktuZmZmw9XKFo8DgTMj4uqIWAZ8HjhE0kRg\n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\nYRx4mJmZWWEceJiZmVlhHHiYmZlZYRx4mJmZWWEceJiZmVlhHHiYmZlZYRx4mJmZWWEceJiZmVlh\nHHiYmZlZYRx4mJmZWWEceJiZmVlhHHiYmZlZYRx4mJmZWWEceJiZmVlhHHiYmZlZYRx4mJmZWWEc\neJiZmVlhWh54SNpF0v2S9izbdrGkzZIG8897y9LmSLpV0nJJ57am1GZmZjYcLQ08JO0CLAD2qkjq\nBV4B7Jgfh+T8XcC1wG3AYcAsSfMKK7CZmZltk1a3ePQDV5RvkDQRmA3cEhFrImJ1RKzNyccC3cAZ\nEbEEOBuYX2SBzczMbPhaHXjMj4jPASrbdhCpXHdIekLS9ZL2yGlzgYURsR4gIu4EZhVaYjMzMxu2\nlgYeEbG0yuZZwD3ACaQgZAD4Qk7rBpZU5B+Q1DNqhTQzM7MRM6nVBagUEVcCV5aeSzoFuF/S00hB\nSKUNwFRgVb39Ll58OpMnbx2fzJjRx8yZfdtcZjMzs07X399Pf3//VttWrap7aR2Wtgs8qngUmAjs\nDqwgjf8oNw3YONROZs++iJ6eQ0e+dGZmZmNAX18ffX1bfxlftGgRvb29I3qcVo/xeApJ50kqr/nh\nwCDwIGk2y+FlefcGukgBiZmZmbW5dmzxuAM4R9IjpPJdDFweEesl3QxMkzQvIi4HzgJujIhoYXnN\nzMysQe0SeDwZOETEFZJmAVeTxnR8jTRtlogYlHQS0C/pAlJLyFHFF9fMzMyGoy0Cj4iYWPH8bHKw\nUSXvAkn7kBYZWxgRKwsoopmZmY2Atgg8mhURjwLXt7ocZmZm1py2G1xqZmZmY5cDDzMzMyuMAw8z\nMzMrjAMPMzMzK4wDDzMzMyuMAw8zMzMrjAMPMzMzK4wDDzMzMyuMAw8zMzMrjAMPMzMzK4wDDzMz\nMyuMAw8zMzMrjAMPMzMzK4wDDzMzMyuMAw8zMzMrjAMPMzMzK4wDDzMzMyuMAw8zMzMrjAMPMzMz\nK4wDDzMzMyuMAw8zMzMrjAMPMzMzK4wDDzMzMytMywMPSbtIul/SnmXb5ki6VdJySedW5K+ZZmZm\nZu2tpYGHpF2ABcBeZdu6gGuB24DDgFmS5g2VZmZmZu2v1S0e/cAVFduOBbqBMyJiCXA2ML+BNDMz\nM2tzrQ485kfE5wCVbZsLLIyI9QARcSdwYJ20WQWW18zMzLZBSwOPiFhaZXM3sKRi26CknhppAznN\n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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x11d7aa20>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('min_similarity:', 0.5, 'K:', 1)\n"
     ]
    }
   ],
   "source": [
    "#计算相似度\n",
    "sim_mat = similarity_matrix(mat=train_mat.T, model='consine', minimum_common_items=3)# 矩阵转置\n",
    "neighbors = np.argsort(-np.array(sim_mat)) # 获取近邻\n",
    "sim_sort = -1*np.sort(-np.array(sim_mat)) # 获取对应近邻的相似度\n",
    "\n",
    "# 获取近邻数K\n",
    "min_similarity = 0.5\n",
    "K = get_K(sim_mat, min_similarity=min_similarity)\n",
    "print('min_similarity:',min_similarity,'K:',K)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "mae:0.8277; rmse:1.1497\n",
      "recall:0.0092; precision:0.0194\n"
     ]
    }
   ],
   "source": [
    "# 预测评分矩阵\n",
    "r_pred = prediction(train_mat=train_mat, sim_mat=sim_mat, K=5, model='item_based')\n",
    "\n",
    "# 获取推荐列表\n",
    "n = 10\n",
    "topn = get_topn(r_pred=r_pred, train_mat=train_mat, n=n)\n",
    "\n",
    "# 评估算法\n",
    "mae, rmse = mae_rmse(r_pred=r_pred, test_mat=test_mat)\n",
    "print('mae:%.4f; rmse:%.4f'%(mae,rmse))\n",
    "recall, precision = recall_precision(topn=topn, test_mat=test_mat)\n",
    "print('recall:%.4f; precision:%.4f'%(recall,precision))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python [conda root]",
   "language": "python",
   "name": "conda-root-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
